package cn.rengy.web.framework.generate.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.ModelAndView;

import cn.rengy.tool.core.util.ExceptionPrintUtils;
import cn.rengy.web.framework.id.IdGenerator;
import cn.rengy.web.framework.property.service.PropertyService;
import cn.rengy.web.framework.sql.DbService;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateNotFoundException;

@Service
public class GenerateService {
	@Autowired
	private Configuration freeMarkerConfiguration;
	private static Logger logger = LoggerFactory.getLogger(GenerateService.class);
	@Autowired
	private DbService dbService;
	@Autowired
	private PropertyService propertyService;
	@Autowired
	private IdGenerator idGenerator;
	
	public Template getTemplate(String path) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
		Template template =freeMarkerConfiguration.getTemplate(path);
		return template;
	}
	/**
	 * 生成常量
	 * @throws IOException 
	 * @throws ParseException 
	 * @throws MalformedTemplateNameException 
	 * @throws TemplateNotFoundException 
	 */
	public void generateConstants() throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException {
		Template templateJava=freeMarkerConfiguration.getTemplate("/view/develop/constants/AppConstants.ftl");
		Template templateJs=freeMarkerConfiguration.getTemplate("/view/develop/constants/constant.ftl");
		File targetDirectory = new File("src/main/java/com/uniontrip/custom");
		Map<String,Object> paramMap=new HashMap<String,Object>();
		List<Map<String,Object>> constantsList=this.dbService.queryForList("select_generate_constants");
		paramMap.put("constantsList", constantsList);
		write(new File(targetDirectory,"AppConstants.java"),paramMap,templateJava);
		write(new File(targetDirectory,"constant.js"),paramMap,templateJs);
	}
	/*
	 * 返回freemarker视图
	 */
	public ModelAndView generateView(int pageid){
		ModelAndView view=new ModelAndView();
		Map<String,Object> param=new HashMap<String,Object>();
		param.put("id", pageid);
		Map<String,Object> page=this.dbService.queryForMap("select_get_sys_page",pageid);
		String code_type=(String)page.get("code_type");
		view.setViewName((String)page.get("template_name"));
		view.addAllObjects(page);
		view.addObject("page_id", pageid);
		if(code_type.equals("form")){
			param.put("page_id", page.get("main_page_id"));
		}else{
			param.put("page_id", pageid);
		}
		List<Map<String, Object>> columnList=this.dbService.queryForListMapParameter("select_sys_grid_column_bypageid", param);
		view.addObject("columnList",columnList);
		view.addObject("jsname","/authenticated/generate/view/"+(pageid+1));
		return view;
	}
	
	
	
	/**
	 * 生成页面
	 * @param realPath
	 * @param paramMap
	 * @throws Exception
	 */
	@Transactional(rollbackFor = Exception.class)
	public void generatePage(String realPath,Map<String,Object> paramMap) throws  Exception{
		Template templateHtml=null;
		Template templateJs=null;
		
		String relative_path=(String)paramMap.get("relative_path");
		if(!relative_path.endsWith("/")){
			relative_path+="/";
		}
		String code_type=(String)paramMap.get("code_type");
		String edit_type=(String)paramMap.get("edit_type");
		String table_name=(String)paramMap.get("table_name");
		File targetDirectory=new File(realPath+"/"+relative_path);
		//targetDirectory.lastModified()
		if(targetDirectory.exists()){
			//throw new Exception("目录已存在");
		}else{
			if(!targetDirectory.mkdirs()){
				throw new Exception("执行mkdirs失败");
			}
		}
		
		//1.查询gridcolum是否已经存在，存在则一个表生产多个页面，生成的gridsql带页面id前缀
		//int countTableName=this.dbService.queryForObject("count_grid_column_by_table_name", Integer.class,table_name);
		//保存page信息
		paramMap.put("template_name","/view/develop/templates/searchEdit.html.ftl");
		//long page_id=this.dbService.updateReturnGeneratedKeys("insert_sys_page", paramMap);
		Long page_id=idGenerator.nextId();
		//String sqlPrefix="";
		//if(countTableName>0){
		//	sqlPrefix=""+page_id;
		//}
		String sqlname="grid_"+page_id+"_"+table_name;
		//生成gridsql
		Map<String,Object> generateParam=new HashMap<String,Object>();
		
		generateParam.put("table_name",table_name);
		generateParam.put("generate_type","gridsql");
		generateParam.put("sqlname",sqlname );
		generateSql(generateParam);
		paramMap.put("sqlname",sqlname);
		
		//Map<String,Object> map=new HashMap<String,Object>();
		paramMap.put("page_id", page_id);
		//生成gridcolum
		String schema_name=this.propertyService.getSchemaName();
		paramMap.put("schema_name", schema_name);
		this.dbService.updateMapParameter("insert_sys_grid_column", paramMap);
		
		//生成html文件
		templateHtml=freeMarkerConfiguration.getTemplate("/view/develop/templates/searchEdit.html.ftl");
		//long js_page_id=this.dbService.updateReturnGeneratedKeys("insert_sys_page", paramMap);
		//paramMap.put("jsname",page_id);
		write(new File(targetDirectory,page_id+".html"),paramMap,templateHtml);
	}
	
	
	
	public void write(File targetFile,Map<String,Object> map,Template template) {
		OutputStreamWriter out=null;
		try {
			out = new OutputStreamWriter(new FileOutputStream(targetFile),"UTF-8");
			template.process(map, out);
	        out.flush();
		} catch (Exception e) {
			logger.error("生成文件异常");
			logger.error(ExceptionPrintUtils.getTrace(e));
		}finally{
			try {
				if(out!=null){
					out.close();	
				}
			} catch (IOException e) {}
		}
	}
	/**
	 * 通过表名生成gridsql
	 * @param table_name
	 */
	public void generateSql(Map<String,Object> paramMap){
		String table_name=(String)paramMap.get("table_name");
		String type=(String)paramMap.get("generate_type");
		String sqlname=(String)paramMap.get("sqlname");
		if(StringUtils.isBlank(sqlname)){
			sqlname="grid_"+table_name;
		}
		List<Map<String, Object>> columnList=getColumnList(table_name);
		if("gridsql".equals(type)){
			generateSelectSql(table_name, columnList, sqlname);
			StringBuilder select_count=new StringBuilder("select count(*) from ").append(table_name);
			StringBuilder delete=new StringBuilder("update ").append(table_name).append(" set is_deleted=1 where id in (:ids)");
			this.dbService.update("insert_generate_gridsql", sqlname+"-count",select_count.toString());
			this.dbService.update("insert_generate_gridsql", sqlname+"-delete",delete.toString());
			generateInsertSql(table_name, columnList, sqlname+"-insert");
			generateUpdateSql(table_name, columnList,sqlname+"-update");
		}else if("insert".equals(type)){
			generateInsertSql(table_name, columnList, "insert_"+table_name);
		}else if("update".equals(type)){
			generateUpdateSql(table_name, columnList, "update_"+table_name);
		}else if("get".equals(type)){
			this.dbService.update("insert_generate_gridsql", "select_get_"+table_name ,"select * from "+table_name+" where id=:id");
		}
	}
	public List<Map<String, Object>> getColumnList(String table_name){
		return this.dbService.queryForList("select_table_info",this.propertyService.getSchemaName(), table_name);
	}
	/**
	 * 生成select sql
	 * @param table_name
	 * @param columnList
	 * @param sql_name
	 */
	private void generateSelectSql(String table_name,List<Map<String, Object>> columnList,String sql_name){
		StringBuilder select=new StringBuilder("select ");
		for(Map<String, Object> map:columnList){
			Object name=map.get("COLUMN_NAME");
			select.append(name).append(",");
		}
		select.deleteCharAt(select.length()-1);
		select.append(" from ").append(table_name);
		this.dbService.update("insert_generate_gridsql", sql_name,select.toString());
	}
	private void generateUpdateSql(String table_name,List<Map<String, Object>> columnList,String sql_name){
		StringBuilder update=new StringBuilder("update ").append(table_name).append(" set ");
		for(Map<String, Object> map:columnList){
			Object name=map.get("COLUMN_NAME");
			if(name.equals("id")
					||name.equals("creator_id")||name.equals("creator_name")
					||name.equals("create_time")||name.equals("is_deleted"))
				continue;
			update.append(name).append("=:").append(name).append(",");
		}
		update.deleteCharAt(update.length()-1);
		update.append(" where id=:id");
		this.dbService.update("insert_generate_gridsql", sql_name,update.toString());
	}
		
		
	private void generateInsertSql(String table_name,List<Map<String, Object>> columnList,String sql_name){
		StringBuilder insert=new StringBuilder("insert into ").append(table_name).append("(");
		for(Map<String, Object> map:columnList){
			Object name=map.get("COLUMN_NAME");
			if(name.equals("is_deleted"))
				continue;
			insert.append(name).append(",");
		}
		insert.deleteCharAt(insert.length()-1);
		insert.append(") values (");
		for(Map<String, Object> map:columnList){
			Object name=map.get("COLUMN_NAME");
			if(name.equals("is_deleted"))
				continue;
			else{
				insert.append(":").append(name).append(",");
			}
		}
		insert.deleteCharAt(insert.length()-1);
		insert.append(")");
		this.dbService.update("insert_generate_gridsql", sql_name ,insert.toString());
	}
	
	public List<Map<String, Object>> getAllTables(){
		
		return this.dbService.queryForList("select_all_tables", this.propertyService.getSchemaName());
		
	}
	
	public List<Map<String, Object>> getTable(String tableName){
		
		return this.dbService.queryForList("select_get_tables", this.propertyService.getSchemaName(),tableName);
		
	}
}
